/* ***** BEGIN LICENSE BLOCK *****
Copyright 2010, 2011 CZ.NIC, z.s.p.o.

This file is part of DNSSEC Validator Add-on.

DNSSEC Validator Add-on is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

DNSSEC Validator Add-on is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
DNSSEC Validator Add-on.  If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK ***** */

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  //only fire when loading
  if (changeInfo.status != 'loading') return;

  var res = setTimeout(function() { dnssecExtension.processNewURL(tab); }, 0);
});

var dnssecExtension = {
  debugOutput: false,

  processNewURL: function(tab) {
    chrome.pageAction.show(tab.id);
    var aLocationURI = tab.url.match(/^(.*):\/\/(.[^/]+)/);
      
    var scheme = aLocationURI[1];
    var asciiHost = aLocationURI[2];
    var utf8Host = null;

    if (scheme.match(/^chrome/) ||              // Eliminate chrome scheme
        asciiHost == null ||
        asciiHost == '' ||                      // Empty string
        asciiHost.indexOf("\\") != -1 ||        // Eliminate addr containing '\'
        asciiHost.indexOf(":") != -1 ||         // Eliminate IPv6 addr notation
        asciiHost.search(/[A-Za-z]/) == -1) {   // Eliminate IPv4 addr notation

      // Set error mode (no icon)
      dnssecExtHandler.setMode(tab, dnssecExtHandler.DNSSEC_MODE_ERROR);

      return;

    // Eliminate duplicated queries
    } else if (asciiHost == this.oldAsciiHost) {
      return;
    }

    // Check DNS security
    dnssecExtHandler.checkSecurity(tab, asciiHost, utf8Host);
  }

};


/* Get security status through NPAPI library call */

var dnssecExtResolver = {

  // Called when request is not cached already
  doNPAPIvalidation: function(dn, resolvipv4, resolvipv6) {
    var plugin = document.getElementById("dnssec-plugin");

    // Get DNS resolver address(es)
    //var nameserver = "89.185.235.199";
    var nameserver = "217.31.204.130";
    //var nameserver = "149.20.64.20";

    // Create variable to pass options
    var options = 0;
    if (dnssecExtension.debugOutput) options |= dnssecExtNPAPIConst.NPAPI_INPUT_FLAG_DEBUGOUTPUT;
    //if (dnssecExtPrefs.getBool("usetcp")) options |= dnssecExtNPAPIConst.NPAPI_INPUT_FLAG_USETCP;
    if (resolvipv4) options |= dnssecExtNPAPIConst.NPAPI_INPUT_FLAG_RESOLVIPV4;
    if (resolvipv6) options |= dnssecExtNPAPIConst.NPAPI_INPUT_FLAG_RESOLVIPV6;
    
    if (dnssecExtension.debugOutput)
      dump(dnssecExtension.debugPrefix + 'Validation parameters: \"'
           + dn + '; ' + options + '; ' + nameserver + '\"\n');

    var res = null;
 
    res = plugin.Validate(dn, parseInt(options), nameserver);
    return res;
  },


  // Get validated data from cache or by NPAPI call
  getValidatedData: function(dn, v4, v6) {

    var ext = dnssecExtension;
    var resArr;

    resArr = this.doNPAPIvalidation(dn, v4, v6);

    var resaddrs = resArr[0];
    var res = resArr[3];

    return [resaddrs, res];
  },

};


/* Utility class to handle manipulations of the dnssec indicators in the UI */
var dnssecExtHandler = {

  // Mode strings used to control CSS display

  // Domain and also connection are secured
  DNSSEC_MODE_CONNECTION_DOMAIN_SECURED           : "securedConnectionDomain",
  // Domain and also connection are secured but browser's IP address is invalid
  DNSSEC_MODE_CONNECTION_DOMAIN_INVIPADDR_SECURED : "securedConnectionDomainInvIPaddr",
  // Connection is secured, but domain name does not exist
  DNSSEC_MODE_CONNECTION_NODOMAIN_SECURED         : "securedConnectionNoDomain",
  // Non-existent domain and also connection are secured but browser's IP address is invalid
  DNSSEC_MODE_CONNECTION_NODOMAIN_INVIPADDR_SECURED : "securedConnectionNoDomainInvIPaddr",
  // Connection is secured, but domain name signature is invalid
  DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_SECURED     : "securedConnectionInvSigDomain",
  // Connection is secured, but domain name signature and browser's IP address are invalid
  DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_INVIPADDR_SECURED : "securedConnectionInvSigDomainInvIPaddr",
  // Domain is secured and has a valid signature, but no chain of trust
  DNSSEC_MODE_DOMAIN_SIGNATURE_VALID              : "validDomainSignature",
  // Authoritative domain is secured and has a valid signature, but no chain of trust
  DNSSEC_MODE_AUTH_DOMAIN_SIGNATURE_VALID         : "validAuthDomainSignature",
  // Domain is secured and has a valid signature, but browser's IP address is invalid
  DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_VALID    : "validDomainSignatureInvIPaddr",
  // Domain is secured, but it has an invalid signature
  DNSSEC_MODE_DOMAIN_SIGNATURE_INVALID            : "invalidDomainSignature",
  // Domain is secured, but signature and browser's IP address are invalid
  DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_INVALID  : "invalidDomainSignatureInvIPaddr",
  // No DNSSEC signature
  DNSSEC_MODE_DOMAIN_UNSECURED                    : "unsecuredDomain",
  // No NSEC/NSEC3 for non-existent domain name
  DNSSEC_MODE_NODOMAIN_UNSECURED                  : "unsecuredNoDomain",
  // Non-existent domain is secured and has a valid signature, but no chain of trust
  DNSSEC_MODE_NODOMAIN_SIGNATURE_VALID            : "validNoDomainSignature",
  // Authoritative non-existent domain is secured and has a valid signature, but no chain of trust
  DNSSEC_MODE_AUTH_NODOMAIN_SIGNATURE_VALID       : "validAuthNoDomainSignature",
  // Non-existent domain is secured and has a valid signature, but browser's IP address is invalid
  DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_VALID  : "validNoDomainSignatureInvIPaddr",
  // Non-existent domain is secured, but it has an invalid signature
  DNSSEC_MODE_NODOMAIN_SIGNATURE_INVALID          : "invalidNoDomainSignature",
  // Non-existent domain is secured, but signature and browser's IP address are invalid
  DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_INVALID : "invalidNoDomainSignatureInvIPaddr",
  // Getting security status
  DNSSEC_MODE_ACTION : "actionDnssec",
  // Error or unknown state occured
  DNSSEC_MODE_ERROR : "errorDnssec",

  // Tooltips
  DNSSEC_TOOLTIP_SECURED   : "securedTooltip",
  DNSSEC_TOOLTIP_UNSECURED : "unsecuredTooltip",
  DNSSEC_TOOLTIP_ACTION    : "actionTooltip",

  checkSecurity : function(tab, asciiHost, utf8Host) {

    // Set action state
    this.setMode(tab, this.DNSSEC_MODE_ACTION);

    var resolvipv4 = true; // No IPv4 resolving as default
    var resolvipv6 = false; // No IPv6 resolving as default
    var addr = null;

    // Resolve IPv4 if no version is desired
    if (!resolvipv4 && !resolvipv6) resolvipv4 = true;

    // Get validated data from cache or by NPAPI call
    var resaddrs = '';
    var res = -1;
    var resArr = dnssecExtResolver.getValidatedData(asciiHost, resolvipv4, resolvipv6);
    resaddrs = resArr[0];
    res = resArr[1];

    var invipaddr = false;

    this.setSecurityState(tab, res, false);
  },

  setSecurityState : function(tab, state, invipaddr) {
    switch (state) {
      case dnssecExtNPAPIConst.NPAPI_EXIT_CONNECTION_DOMAIN_SECURED:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_DOMAIN_SECURED);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_DOMAIN_INVIPADDR_SECURED);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_CONNECTION_NODOMAIN_SECURED:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_NODOMAIN_SECURED);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_NODOMAIN_INVIPADDR_SECURED);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_CONNECTION_INVSIGDOMAIN_SECURED:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_SECURED);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_INVIPADDR_SECURED);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_DOMAIN_SIGNATURE_VALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_DOMAIN_SIGNATURE_VALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_VALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_AUTH_DOMAIN_SIGNATURE_VALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_AUTH_DOMAIN_SIGNATURE_VALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_VALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_DOMAIN_SIGNATURE_INVALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_DOMAIN_SIGNATURE_INVALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_INVALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_NODOMAIN_SIGNATURE_VALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_NODOMAIN_SIGNATURE_VALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_VALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_AUTH_NODOMAIN_SIGNATURE_VALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_AUTH_NODOMAIN_SIGNATURE_VALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_VALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_NODOMAIN_SIGNATURE_INVALID:
        if (!invipaddr) {
          this.setMode(tab, this.DNSSEC_MODE_NODOMAIN_SIGNATURE_INVALID);
        } else {
          this.setMode(tab, this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_INVALID);
        }
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_DOMAIN_UNSECURED:
        this.setMode(tab, this.DNSSEC_MODE_DOMAIN_UNSECURED);
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_NODOMAIN_UNSECURED:
        this.setMode(tab, this.DNSSEC_MODE_NODOMAIN_UNSECURED);
        break;
      case dnssecExtNPAPIConst.NPAPI_EXIT_UNKNOWN:
      case dnssecExtNPAPIConst.NPAPI_EXIT_FAILED:
      default:
        this.setMode(tab, this.DNSSEC_MODE_ERROR);
        break;
    }

  },

  setMode : function(tab, newMode) {
    switch(newMode) {
      case this.DNSSEC_MODE_CONNECTION_DOMAIN_SECURED:
      case this.DNSSEC_MODE_CONNECTION_DOMAIN_INVIPADD_SECURED:
      case this.DNSSEC_MODE_CONNECTION_NODOMAIN_SECURED:
      case this.DNSSEC_MODE_CONNECTION_NODOMAIN_INVIPADD_SECURED:
            chrome.pageAction.setIcon({path:"icon_green.png", tabId:tab.id});
            break;
      case this.DNSSEC_MODE_DOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_NODOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_AUTH_DOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_AUTH_NODOMAIN_SIGNATURE_VALID:
            chrome.pageAction.setIcon({path:"icon_orange.png", tabId:tab.id});
            break;
      case this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_SECURED:
      case this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_INVIPADDR_SECURED:
      case this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_DOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_NODOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_VALID:
            chrome.pageAction.setIcon({path:"icon_red.png", tabId:tab.id});
            break;
      case this.DNSSEC_MODE_DOMAIN_UNSECURED:
      case this.DNSSEC_MODE_NODOMAIN_UNSECURED:
            chrome.pageAction.setIcon({path:"icon_grey2.png", tabId:tab.id});
            break;
      case this.DNSSEC_MODE_ACTION:
            chrome.pageAction.setIcon({path:"icon_action.png", tabId:tab.id});
            break;
      case this.DNSSEC_MODE_ERROR:
            chrome.pageAction.setIcon({path:"icon_grey.png", tabId:tab.id});
            break;
      default:
            break;
    }
    chrome.pageAction.setTitle({tabId:tab.id, title:newMode});
    //this.setSecurityMessages(tab, newMode);
  },

  /*setSecurityMessages : function(tab, newMode) {
    switch (newMode) {
      // Both domain and connection are secured
      case this.DNSSEC_MODE_CONNECTION_DOMAIN_SECURED:
      // Domain and also connection are secured but browser's IP address is invalid
      case this.DNSSEC_MODE_CONNECTION_DOMAIN_INVIPADDR_SECURED:
      // Both non-existent domain and connection are secured
      case this.DNSSEC_MODE_CONNECTION_NODOMAIN_SECURED:
      // Non-existent domain and also connection are secured but browser's IP address is invalid
      case this.DNSSEC_MODE_CONNECTION_NODOMAIN_INVIPADDR_SECURED:
      // Connection is secured, but domain signature is invalid
      case this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_SECURED:
      // Connection is secured, but domain signature and browser's IP address are invalid
      case this.DNSSEC_MODE_CONNECTION_INVSIGDOMAIN_INVIPADDR_SECURED:
        this.setTitle(tab, this.DNSSEC_TOOLTIP_SECURED);
        break;
      // Domain signature is valid
      case this.DNSSEC_MODE_DOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_AUTH_DOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_VALID:
      // Domain signature is invalid
      case this.DNSSEC_MODE_DOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_INVIPADDR_DOMAIN_SIGNATURE_INVALID:
      // Non-existent domain signature is valid
      case this.DNSSEC_MODE_NODOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_AUTH_NODOMAIN_SIGNATURE_VALID:
      case this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_VALID:
      // Non-existent domain signature is invalid
      case this.DNSSEC_MODE_NODOMAIN_SIGNATURE_INVALID:
      case this.DNSSEC_MODE_INVIPADDR_NODOMAIN_SIGNATURE_INVALID:
      // No DNSSEC signature
      case this.DNSSEC_MODE_DOMAIN_UNSECURED:
      case this.DNSSEC_MODE_NODOMAIN_UNSECURED:
        this.setTitle(tab, this.DNSSEC_TOOLTIP_UNSECURED);
        break;
      // Getting security status
      case this.DNSSEC_MODE_ACTION:
        this.setTitle(tab, this.DNSSEC_TOOLTIP_ACTION);
        break;
      // Unknown
      default:
        this.setTitle(tab, undefined);
      }
  },

  setTitle: function(tab, newTitle) {
    switch (newTitle) {
      case this.DNSSEC_TOOLTIP_SECURED:
        chrome.pageAction.setTitle({tabId:tab.id, title:"DNSSEC secured"});
        break;
      case this.DNSSEC_TOOLTIP_UNSECURED:
        chrome.pageAction.setTitle({tabId:tab.id, title:"DNSSEC unsecured"});
        break;
      case this.DNSSEC_TOOLTIP_ACTION:
        chrome.pageAction.setTitle({tabId:tab.id, title:"DNSSEC lookup in progress"});
        break;
      default: 
        chrome.pageAction.setTitle({tabId:tab.id, title:""});
        break;
    }
  }*/

};
